package com.example.xiaomiao.Service.Impl;

import com.example.xiaomiao.DO.Picture;
import com.example.xiaomiao.DO.User;
import com.example.xiaomiao.DTO.Return;
import com.example.xiaomiao.DTO.UserGetResponseDTO;
import com.example.xiaomiao.DTO.UpdateProfilePictureRequestDTO;
import com.example.xiaomiao.Mapper.PictureMapper;
import com.example.xiaomiao.Mapper.UserMapper;
import com.example.xiaomiao.Service.UserService;
import com.example.xiaomiao.Util.CacheDataBaseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.FileOutputStream;
import java.security.MessageDigest;
import java.util.Base64;
import java.util.concurrent.TimeUnit;

import static com.example.xiaomiao.Util.MyConstants.*;

@Service
public class UserServiceImpl implements UserService {
    @Resource
    UserMapper userMapper;
    @Resource
    PictureMapper pictureMapper;
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    CacheDataBaseUtil cacheDataBaseUtil;
    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Return update(int userId, User newMessage) {
        try{
            return update1(userId,newMessage);
        } catch (Exception e){
            return Return.fail(1,"更新失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Return updateProfilePicture(int userId, UpdateProfilePictureRequestDTO updatePictureRequestData) {
        try {
            return updateProfilePicture1(userId,updatePictureRequestData);
        } catch (Exception e){
            return Return.fail(1,"更新失败");
        }
    }

    @Override
    public Return get(int userId) {
        User user = cacheDataBaseUtil.selectById(USER_KEY,userId,User.class, userId2 -> userMapper.getUserById(userId2),USER_CACHE_TTL, TimeUnit.HOURS);
        return Return.ok(new UserGetResponseDTO(user));
    }

    @Override
    public Return logout(int userId) {
        try {
            stringRedisTemplate.delete(TOKEN_KEY+PROJECT_NAME+userId);
        } catch (Exception e){
            logger.error(e.getMessage());
            return Return.fail(1,"登出失败");
        }
        return Return.ok();
    }

    @Transactional(rollbackFor = Exception.class)
    public Return update1(int userId, User newMessage) {
        try{
            cacheDataBaseUtil.updateById(USER_KEY,userId,newMessage,(userId2,newMessage2) -> userMapper.updateUser(userId2,newMessage2));
            if(newMessage.getPassword() != null){
                String telephone = userMapper.getTelephone(userId);
                stringRedisTemplate.delete(USER_KEY+telephone);
            }
            return Return.ok();
        }catch (Exception e){
            logger.error(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Return updateProfilePicture1(int userId, UpdateProfilePictureRequestDTO updatePictureRequestData) {
        String base64 = updatePictureRequestData.getProfile_picture();
        if(base64.contains(",")){
            base64 = base64.split(",")[1];
        }
        String md5 = null;
        try {
            byte[] imageData = Base64.getDecoder().decode(base64);
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(imageData);
            StringBuilder md5Value = new StringBuilder(32);
            for (byte b : digest) {
                md5Value.append(String.format("%02x", b)); // 每个字节转 2 位十六进制
            }
            md5 = md5Value.toString();
            if(!cacheDataBaseUtil.tryLock(PICTURE_KEY,md5,LOCK_TTL, TimeUnit.MINUTES))
                return Return.fail(2,"用户较多，请稍后重试");
            if (cacheDataBaseUtil.isContainsById(PICTURE_KEY, md5, md52 -> pictureMapper.getPictureId(md52), PICTURE_CACHE_TTL, TimeUnit.HOURS)) {
                int pictureId = cacheDataBaseUtil.selectById(PICTURE_KEY, md5, Integer.class, md52 -> pictureMapper.getPictureId(md52), PICTURE_CACHE_TTL, TimeUnit.HOURS);
                cacheDataBaseUtil.updateById(USER_KEY,userId,pictureId,(userId2,pictureId2) -> userMapper.updateProfilePicture(userId2,pictureId2));
                return Return.ok();
            }
            Picture picture = new Picture(md5);
            pictureMapper.addPicture(picture);
            int pictureId = picture.getPicture_id();
            stringRedisTemplate.opsForValue().set(PICTURE_KEY, String.valueOf(pictureId),PICTURE_CACHE_TTL, TimeUnit.HOURS);
            String path = PICTURE_ADDRESS + pictureId + ".jpg";
            FileOutputStream fos = new FileOutputStream(path);
            fos.write(imageData);
            cacheDataBaseUtil.updateById(USER_KEY,userId,pictureId,(userId2,pictureId2) -> userMapper.updateProfilePicture(userId2,pictureId2));
            return Return.ok();
        } catch (Exception e){
            logger.error(e.getMessage());
            throw new RuntimeException(e);
        } finally {
            cacheDataBaseUtil.unlock(PICTURE_KEY,md5);
        }
    }
}
